﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BasePlatformNet;
using L9SubSet.WriteAddrPro;
using System.Threading;
using BasePlatformCommon;
using System.IO;
//using System.Xml.Linq;
using System.Xml.Serialization;

namespace L9SubSet
{
	public partial class Form_WriteAddrPro : Form
	{
		public int dmx_w_type = 0;

		public int subNum_new = 0;
		public int lampNum_new = 0;

		private Form_MainSet parent = null;

		private bool usePin4 = false;
		private List<AddrSub> subList = null;
		private bool initDone = false;
		private int headRowNum = 2;
		private int currentSubIndex = -1;

		private List<CheckBox> portCheckBoxList = null;
		private bool portCheckBoxIsShown = false;

		public int startLampAddrQuick = 1;			// 首灯地址
		public int startLampNumQuick = 1;			// 起始灯具号
		public int endLampNumQuick = 1;				// 结束灯具号
		public int portIndexQuick = 0;				// 应用到端口
		public int[] channelArrayQuick = null;		// 灯具通道数数组
		public bool firstShowQuickEdit = true;		// 第一次显示快速编辑界面

		private BaseCoreNet baseCoreNet = null;		// 底层通信平台引用（单例）

		private int subIndexEmpty = -1;
		private int portIndexEmpty = -1;

		private int writePortTimeGap = -1;			// 端口写址间隔时间

		private bool writeDmxIsProcessing = false;	// 写址操作正在进行中
		private int needWriteNum = 0;				// 写入操作需要处理的端口数量
		private bool forceStop = false;				// 强制停止写入操作标记

		// 事件声明
		public event EventHandler<WriteProcessChangedEventArgs> WriteProcessChangedEvent;	//【事件】写址进度变化
		public event EventHandler<EventArgs> WriteProcessDoneEvent;			//【事件】写址完成
		public event EventHandler<EventArgs> WriteProcessStopedEvent;		//【事件】写址强制停止

		// 委托定义与声明
		private delegate void ShowDoneMessageDelegate();
		private ShowDoneMessageDelegate showDoneMessageDelegate;
		private delegate void WriteProcessChangedDelegate(WriteProcessChangedEventArgs e);
		private WriteProcessChangedDelegate writeProcessChangedDelegate;
		private delegate void WriteProcessDoneDelegate();
		private WriteProcessDoneDelegate writeProcessDoneDelegate;

		private string section = "WriteAddrPro";							// 多语言文件配置节名称

		private string tip = "提示";											// MessageBox 题头

        private int _subCount;
        public int SubCount
        {
            get { return _subCount; }
        }

		/*****************************************************************************************/

		// 构造函数
		public Form_WriteAddrPro(int dmx_w_type, bool usePin4, Form_MainSet parent)
		{
			InitializeComponent();

			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
			this.Font = new System.Drawing.Font(this.Font.Name, 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel, ((byte)(134)));

			this.parent = parent;
            _subCount = parent.getSubControllerNum();

			initEnvironment(dmx_w_type, usePin4);
		}

		// 设置底层通信平台引用
		public void setBaseCoreNet(BaseCoreNet baseCoreNet)
		{
			this.baseCoreNet = baseCoreNet;
		}

		// 初始化运行环境
		private void initEnvironment(int dmx_w_type, bool usePin4)
		{
			this.dmx_w_type = dmx_w_type;
			this.usePin4 = usePin4;

			subList = new List<AddrSub>();

			portCheckBoxList = new List<CheckBox>();

			// 分控列表右键菜单
			subContextMenuStrip.Items[0].Click += changeToolStripMenuItem_Click;
			subContextMenuStrip.Items[1].Click += clearPortButton_Click;
			subContextMenuStrip.Items[3].Click += delSubButton_Click;

			for (int i = 0; i < 8; i++)
			{
				CheckBox portCheckBox = new System.Windows.Forms.CheckBox();
				portCheckBox.Name = "portCheckBox" + i;
				portCheckBox.BackColor = Color.White;
				portCheckBox.Checked = true;
				portCheckBox.Size = new System.Drawing.Size(15, 18);
				portCheckBox.Visible = false;
				portCheckBox.CheckedChanged += portCheckBox_CheckedChanged;
				portCheckBoxList.Add(portCheckBox);
				portDataGridView.Controls.Add(portCheckBox);
			}

			channelArrayQuick = new int[3] { 3, 3, 3 };

			// 注册事件
			WriteProcessChangedEvent += writeProcessChangedEventHandler;
			WriteProcessDoneEvent += writeProcessDoneEventHandler;
			WriteProcessStopedEvent += writeProcessStopedEventHandler;

			// 委托实例化
			showDoneMessageDelegate = new ShowDoneMessageDelegate(showDoneMessage);
			writeProcessChangedDelegate = new WriteProcessChangedDelegate(writeProcessChanged);
			writeProcessDoneDelegate = new WriteProcessDoneDelegate(writeProcessDone);
			
			// 设置本地化语言
			if (LanguageOper.available == true)
			{
				setLanguageText();
			}
		}

		// 设置本地化语言
		public void setLanguageText()
		{
			if (LanguageOper.available == false)
			{
				return;
			}

			LanguageOper.SetCurrentCulture();

			tip = LanguageOper.ReadValue("Common", "tipStr");

			// 界面控件文字
			this.Text = LanguageOper.ReadValue(section, "writeAddrPro.Text");
			datFileLabel.Text = LanguageOper.ReadValue(section, "datFileLabel.Text");
			datFileButton.Text = LanguageOper.ReadValue(section, "datFileButton.Text");
			subDataGridView.Columns[1].HeaderText = LanguageOper.ReadValue(section, "subDataGridView.HeaderText");
			newSubButton.Text = LanguageOper.ReadValue(section, "newSubButton.Text");
			addSubButton.Text = LanguageOper.ReadValue(section, "addSubButton.Text");
			delSubButton.Text = LanguageOper.ReadValue(section, "delSubButton.Text");
			selectAllSubButton.Text = LanguageOper.ReadValue(section, "selectAllSubButton.Text");
			selectReverseSubButton.Text = LanguageOper.ReadValue(section, "selectReverseSubButton.Text");
			selectRangeSubButton.Text = LanguageOper.ReadValue(section, "selectRangeSubButton.Text");
			quickEditButton.Text = LanguageOper.ReadValue(section, "quickEditButton.Text");
			clearPortButton.Text = LanguageOper.ReadValue(section, "clearPortButton.Text");
			showDmxAddrCheckBox.Text = LanguageOper.ReadValue(section, "showDmxAddrCheckBox.Text");
			changePortLampNumButton.Text = LanguageOper.ReadValue(section, "changePortLampNumButton.Text");
			writePortTimeGapLabel.Text = LanguageOper.ReadValue(section, "writePortTimeGapLabel.Text");
			lampNumLabel.Text = LanguageOper.ReadValue(section, "lampNumLabel.Text");
			gotoButton.Text = LanguageOper.ReadValue(section, "gotoButton.Text");
			writeAddrButton.Text = LanguageOper.ReadValue(section, "writeAddrButton.Text");
			exitButton.Text = LanguageOper.ReadValue(section, "exitButton.Text");
            btnSave.Text = LanguageOper.ReadValue(section, "btnSave.Text");
			if (LanguageOper.LocalLanguage != LanguageEnum.EN)
			{
				writePortTimeGapLabel.Location = new Point(402, 420);
			}
			else
			{
				writePortTimeGapLabel.Location = new Point(412, 420);
			}
		}

		// 显示写址完成提示信息
		private void showDoneMessage()
		{
			string msg = "DMX地址写入完成";
			if (LanguageOper.available == true)
			{
				msg = LanguageOper.ReadValue(section, "msgStr.0");
			}

			MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
		}

		// 写址进度变化
		private void writeProcessChanged(WriteProcessChangedEventArgs e)
		{
			if (e.processValue >= 0 && e.processValue <= 100)
			{
				writeDmxProgressBar.Value = e.processValue;
				writeDmxLabel.Text = e.processValue + "%";
			}
		}

		// 写址完成（与写址强制停止共用）
		private void writeProcessDone()
		{
			subDataGridView.Enabled = true;
			portDataGridView.Enabled = true;

			datFileButton.Enabled = true;
			newSubButton.Enabled = true;
			addSubButton.Enabled = true;
			delSubButton.Enabled = true;
			selectAllSubButton.Enabled = true;
			selectReverseSubButton.Enabled = true;
			selectRangeSubButton.Enabled = true;
			quickEditButton.Enabled = true;
			clearPortButton.Enabled = true;
			changePortLampNumButton.Enabled = true;
			showDmxAddrCheckBox.Enabled = true;
			writePortTimeGapLabel.Enabled = true;
			writePortTimeGapLabel2.Enabled = true;
			writePortTimeGapTextBox.Enabled = true;
			lampNumLabel.Enabled = true;
			gotoTextBox.Enabled = true;
			gotoButton.Enabled = true;
			exitButton.Enabled = true;

			writeDmxProgressBar.Value = 0;
			writeDmxLabel.Text = writeDmxProgressBar.Value + "%";
			writeAddrButton.Text = LanguageOper.ReadValue(section, "writeAddrButton.Text.0"); ;

			writeDmxIsProcessing = false;
		}

		// 事件处理器 - 写址进度变化
		private void writeProcessChangedEventHandler(object sender, WriteProcessChangedEventArgs e)
		{
			writeAddrButton.Invoke(writeProcessChangedDelegate, e);
		}

		// 事件处理器 - 写址完成
		private void writeProcessDoneEventHandler(object sender, EventArgs e)
		{
			writeAddrButton.Invoke(showDoneMessageDelegate);
			writeAddrButton.Invoke(writeProcessDoneDelegate);
		}

		// 事件处理器 - 写址强制停止
		private void writeProcessStopedEventHandler(object sender, EventArgs e)
		{
			writeAddrButton.Invoke(writeProcessDoneDelegate);
		}

		#region 界面响应

		// 窗口加载后处理
		private void Form_WriteAddrPro_Shown(object sender, EventArgs e)
		{
			newSubButton.PerformClick();
		}

		// 窗体关闭前处理
		private void Form_WriteAddrPro_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (writeDmxIsProcessing == true)
			{
				string msg = "写址操作正在进行中，请先停止该操作";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.1");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
				
				e.Cancel = true;
			}
		}

		// 新建
		private void newSubButton_Click(object sender, EventArgs e)
		{
			initDone = false;

			Form_NewWriteAddrPro paraForm = new Form_NewWriteAddrPro(this);

			parent.addForm("Form_NewWriteAddrPro", paraForm);
			paraForm.setLanguageText();
			DialogResult dr = paraForm.ShowDialog();
			parent.removeForm("Form_NewWriteAddrPro");

			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				// 创建内部数据结构
				buildNewData();

				// 初始化分控列表（左侧）
				initSubDataGridView();

				// 刷新端口数据列表（右侧）
				currentSubIndex = 0;
				updatePortDataGridView(currentSubIndex);
			}

			initDone = true;
		}

		// 添加
		private void addSubButton_Click(object sender, EventArgs e)
		{
			int newSubIndex = subList.Count;
			SubParaWriteAddrPro para = new SubParaWriteAddrPro();
			para.subIndex = newSubIndex;
			for (int i = 0; i < 8; i++)
			{
				para.lampNum[i] = 0;
			}

			Form_SubParaWriteAddrPro paraForm = new Form_SubParaWriteAddrPro(para, "add");
			parent.addForm("Form_SubParaWriteAddrPro", paraForm);
			paraForm.setLanguageText();
			DialogResult dr = paraForm.ShowDialog();
			parent.removeForm("Form_SubParaWriteAddrPro");
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				AddrSub addrSub = new AddrSub(para.lampNum);
				subList.Add(addrSub);

				int newAddIndex = subList.Count - 1;

				string formatStr1 = "控制器{0,-2}";
				string formatStr2 = "控制器{0,-3}";
				if (LanguageOper.available == true)
				{
					formatStr1 = LanguageOper.ReadValue(section, "str.0");
					formatStr2 = LanguageOper.ReadValue(section, "str.1");
				}
				// 更新左侧列表
				if (subList.Count < 100)
				{
					subDataGridView.Rows.Add(true, String.Format(formatStr1 + " ({1})", newAddIndex + 1, subList[newAddIndex].getTotalLampNum()));
				}
				else
				{
					subDataGridView.Rows.Add(true, String.Format(formatStr2 + " ({1})", newAddIndex + 1, subList[newAddIndex].getTotalLampNum()));
				}

				// 选中新添加的分控
				subDataGridView.Rows[newAddIndex].Selected = true;

				// 更新右侧数据区
				currentSubIndex = newAddIndex;
				updatePortDataGridView(currentSubIndex);

				initDone = true;
			}
		}

		// 删除
		private void delSubButton_Click(object sender, EventArgs e)
		{
			if (subDataGridView.SelectedRows.Count <= 0)
			{
				return;
			}

			int delSubIndex = subDataGridView.SelectedRows[0].Index;
			string msg = string.Format("确定要删除控制器 {0} 吗？", delSubIndex + 1);
			if (LanguageOper.available == true)
			{
				msg = string.Format(LanguageOper.ReadValue(section, "msgStr.2"), delSubIndex + 1);
			}
			DialogResult dr = MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				subList.RemoveAt(delSubIndex);
				initSubDataGridView();
				if (subList.Count > 0)
				{
					subDataGridView.Rows[0].Selected = false;
				}
				else
				{
					updatePortDataGridView(-1);
				}
			}
		}

		// 全选
		private void selectAllSubButton_Click(object sender, EventArgs e)
		{
			for (int i = 0; i < subDataGridView.Rows.Count; i++)
			{
				subDataGridView.Rows[i].Cells[0].Value = true;
			}
		}

		// 反选
		private void selectReverseSubButton_Click(object sender, EventArgs e)
		{
			for (int i = 0; i < subDataGridView.Rows.Count; i++)
			{
				if (subDataGridView.Rows[i].Cells[0].Value.ToString().ToLower().Equals("true"))
				{
					subDataGridView.Rows[i].Cells[0].Value = false;
				}
				else
				{
					subDataGridView.Rows[i].Cells[0].Value = true;
				}
			}
		}

		// 范围
		private void moveDownSubButton_Click(object sender, EventArgs e)
		{
			if (subList.Count > 0)
			{
				StartEnd startend = new StartEnd();
				Form_SelectRange selectRange = new Form_SelectRange(subList.Count, startend);
				selectRange.setLanguageText();
				parent.addForm("Form_SelectRange", selectRange);
				DialogResult dr = selectRange.ShowDialog();
				parent.removeForm("Form_SelectRange");
				if (dr == System.Windows.Forms.DialogResult.OK)
				{
					for (int i = 0; i < subDataGridView.Rows.Count; i++)
					{
						if (i >= startend.start && i <= startend.end)
						{
							subDataGridView.Rows[i].Cells[0].Value = true;
						}
						else
						{
							subDataGridView.Rows[i].Cells[0].Value = false;
						}
					}
				}
			}
		}

		// 快速编辑
		private void quickEditButton_Click(object sender, EventArgs e)
		{
			if (subList.Count == 0 || currentSubIndex < 0)
			{
				string msg = "请先选择控制器";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.3");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);

				return;
			}

			if(firstShowQuickEdit == true)
			{
				endLampNumQuick = getMaxPortLampNum(currentSubIndex);
				firstShowQuickEdit = false;
			}
			
			Form_QuickEditAddr quickEditForm = new Form_QuickEditAddr(startLampAddrQuick, startLampNumQuick, endLampNumQuick, portIndexQuick, channelArrayQuick);

			parent.addForm("Form_QuickEditAddr", quickEditForm);
			quickEditForm.setLanguageText();
			DialogResult dr = quickEditForm.ShowDialog();
			parent.removeForm("Form_QuickEditAddr");
			
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				// 保存快速编辑参数
				startLampAddrQuick = quickEditForm.startLampAddr;
				startLampNumQuick = quickEditForm.startLampNum;
				endLampNumQuick = quickEditForm.endLampNum;
				portIndexQuick = quickEditForm.portIndex;
				channelArrayQuick = new int[quickEditForm.channelArray.Length];
				Array.Copy(quickEditForm.channelArray, channelArrayQuick, quickEditForm.channelArray.Length);

				// 根据快速编辑参数修改内部数据
				quickEditHandle(quickEditForm);
			}
		}

		// 显示 DMX512 地址
		private void showDmxAddrCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			calcDmx512Addr();
            updatePortDataGridView(currentSubIndex);
		}

		// 清除地址数据
		private void clearPortButton_Click(object sender, EventArgs e)
		{
			if (currentSubIndex < 0)
			{
				string msg = "请先选择控制器";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.3");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
				
				return;
			}

			Form_DelPortDataMode delModeForm = new Form_DelPortDataMode();
			parent.addForm("Form_DelPortDataMode", delModeForm);
			delModeForm.setLanguageText();
			DialogResult dr = delModeForm.ShowDialog();
			parent.removeForm("Form_DelPortDataMode");
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				if (delModeForm.delMode.Equals("AllSub_AllPort"))
				{
					string msg = "确定所有控制器、所有端口的地址数据吗？";
					if (LanguageOper.available == true)
					{
						msg = LanguageOper.ReadValue(section, "msgStr.4");
					}

					dr = MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);

					if (dr == System.Windows.Forms.DialogResult.OK)
					{
						for (int delSubIndex = 0; delSubIndex < subList.Count; delSubIndex++)
						{
							for (int i = 0; i < 8; i++)
							{
								subList[delSubIndex].portList[i].clearAddrData();
							}
						}
						updatePortDataGridView(currentSubIndex);
					}
				}
				else if (delModeForm.delMode.Equals("SelectedSub_AllPort"))
				{
					string msg = string.Format("确定清除控制器 {0}, 所有端口的地址数据吗？", currentSubIndex + 1);
					if (LanguageOper.available == true)
					{
						msg = string.Format(LanguageOper.ReadValue(section, "msgStr.5"), currentSubIndex + 1);
					}

					dr = MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
					
					if (dr == System.Windows.Forms.DialogResult.OK)
					{
						for (int i = 0; i < 8; i++)
						{
							subList[currentSubIndex].portList[i].clearAddrData();
						}
						updatePortDataGridView(currentSubIndex);
					}
				}
				else if (delModeForm.delMode.Equals("SelectedSub_SelectedPort"))
				{
					StringBuilder sb = new StringBuilder();
					for (int i = 0; i < 8; i++)
					{
						if (subList[currentSubIndex].portList[i].hasChecked)
						{
							sb.Append("," + (i + 1));
						}
					}
					string selectedPortList = sb.ToString();
					if (selectedPortList.Equals(""))
					{
						string msg = "当前未选择任何端口";
						if (LanguageOper.available == true)
						{
							msg = LanguageOper.ReadValue(section, "msgStr.6");
						}
						MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
						return;
					}
					else
					{
						selectedPortList = selectedPortList.Substring(1);

						string msg = string.Format("确定清除控制器 {0}, 端口 {1} 的地址数据吗？", currentSubIndex + 1, selectedPortList);
						if (LanguageOper.available == true)
						{
							msg = string.Format(LanguageOper.ReadValue(section, "msgStr.7"), currentSubIndex + 1, selectedPortList);
						}

						dr = MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
						
						if (dr == System.Windows.Forms.DialogResult.OK)
						{
							for (int i = 0; i < 8; i++)
							{
								if (subList[currentSubIndex].portList[i].hasChecked)
								{
									subList[currentSubIndex].portList[i].clearAddrData();
								}
							}
							updatePortDataGridView(currentSubIndex);
						}
					}
				}
			}
			else
			{
				return;
			}
		}

		// 跳转
		private void gotoButton_Click(object sender, EventArgs e)
		{
			string valueStr = gotoTextBox.Text.Trim();
			int lineNum = -1;
			bool res = int.TryParse(valueStr, out lineNum);
			if (res == false || lineNum < 1)
			{
				return;
			}
			else
			{
				if (lineNum + headRowNum - 1 < portDataGridView.Rows.Count)
				{
					portDataGridView.CurrentCell = portDataGridView.Rows[lineNum + headRowNum - 1].Cells[0];
				}
			}
		}

		// 写入 DMX 地址
		private void writeAddrButton_Click(object sender, EventArgs e)
		{
			// 响应强制停止操作
			if (writeDmxIsProcessing == true)
			{
				string msg = "确认停止当前的写址操作？";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.8");
				}

				DialogResult dr = MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.YesNo, MessageBoxIcon.Question);

				if (dr == System.Windows.Forms.DialogResult.Yes)
				{
					forceStop = true;
				}
				return;
			}

			// 检查端口写址时间间隔
			int tmpWritePortTimeGap = -1;
			bool res = int.TryParse(writePortTimeGapTextBox.Text.Trim(), out tmpWritePortTimeGap);
			if (res == true && tmpWritePortTimeGap >= 12)
			{
				writePortTimeGap = tmpWritePortTimeGap;
			}
			else
			{
				string msg = "端口写址时间间隔应不小于12s";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.9");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
				
				return;
			}

			if (hasEmptyAddrLamp() == true)
			{
				string msg = "当前要写入的数据中存在空地址灯具，请补全。";
				string msg1 = string.Format("具体位置：[ 分控 {0} 端口 {1} ]", subIndexEmpty + 1, portIndexEmpty + 1);
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.10");
					msg1 = string.Format(LanguageOper.ReadValue(section, "msgStr.11"), subIndexEmpty + 1, portIndexEmpty + 1);
				}
				string tipMessage = msg + "\n" + msg1;
				
				MessageBoxEx.Show(this, tipMessage, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
				
				return;
			}

			if (baseCoreNet != null)
			{
				if (baseCoreNet.getActiveDevIndex() == -1)
				{
					string msg = "当前未检测到分控";
					if (LanguageOper.available == true)
					{
						msg = LanguageOper.ReadValue(section, "msgStr.12");
					}
					
					MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
					
					return;
				}

				// 写入 DMX 地址实际动作
				res = startWriteDmxAddr();

				string text = "停止写入";
				if (LanguageOper.available == true)
				{
					text = LanguageOper.ReadValue(section, "writeAddrButton.Text.1");
				}

				if (res == true)
				{
					subDataGridView.Enabled = false;
					portDataGridView.Enabled = false;

					datFileButton.Enabled = false;
					newSubButton.Enabled = false;
					addSubButton.Enabled = false;
					delSubButton.Enabled = false;
					selectAllSubButton.Enabled = false;
					selectReverseSubButton.Enabled = false;
					selectRangeSubButton.Enabled = false;
					quickEditButton.Enabled = false;
					clearPortButton.Enabled = false;
					changePortLampNumButton.Enabled = false;
					showDmxAddrCheckBox.Enabled = false;
					writePortTimeGapLabel.Enabled = false;
					writePortTimeGapLabel2.Enabled = false;
					writePortTimeGapTextBox.Enabled = false;
					lampNumLabel.Enabled = false;
					gotoTextBox.Enabled = false;
					gotoButton.Enabled = false;
					exitButton.Enabled = false;

					writeDmxProgressBar.Value = 0;
					writeDmxLabel.Text = writeDmxProgressBar.Value + "%";
					writeAddrButton.Text = text;
				}
			}
			else
			{
				string msg = "无法找到通信内核引用";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.13");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
			}
		}

		// 退出
		private void exitButton_Click(object sender, EventArgs e)
		{
			this.DialogResult = System.Windows.Forms.DialogResult.OK;
		}

		// 分控列表区 - 右键菜单
		private void subDataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
		{
			if (e.RowIndex == -1 || e.ColumnIndex == 0)
			{
				return;
			}

			if (e.Button == System.Windows.Forms.MouseButtons.Right)
			{
				subDataGridView.Rows[e.RowIndex].Selected = true;
				Control target = (Control)sender;
				Point pt = target.PointToScreen(e.Location);
				pt = new Point(pt.X + subDataGridView.Columns[0].Width + subDataGridView.RowHeadersWidth, pt.Y + (e.RowIndex + 1) * subDataGridView.Rows[0].Height);
				subContextMenuStrip.Show(pt);
			}
		}

		// 分控列表区 - 右键菜单 - 调整端口灯数
		private void changeToolStripMenuItem_Click(object sender, EventArgs e)
		{
			changePortLampNum();
		}

		// 界面按钮 - 调整端口灯数
		private void changePortLampNumButton_Click(object sender, EventArgs e)
		{
			changePortLampNum();
		}

		// 分控列表区 - 分控列表选择项变化
		private void subDataGridView_SelectionChanged(object sender, EventArgs e)
		{
			if (initDone == false)
			{
				return;
			}

			if (subDataGridView.SelectedRows.Count > 0)
			{
				currentSubIndex = subDataGridView.SelectedRows[0].Index;
				updatePortDataGridView(currentSubIndex);
			}
			else
			{
				updatePortDataGridView(-1);
			}
		}

		// 端口数据区 - 单元格结束编辑
		private void portDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
		{
			// 首灯地址
			if (e.RowIndex == 1)
			{
				string valueStr = "";
				if (portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
				{
					valueStr = portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString().Trim();
				}

				int startAddrValue = -1;
				bool res = int.TryParse(valueStr, out startAddrValue);
				if (res == false || startAddrValue < 1)
				{
					string msg = string.Format("端口 {0} 首灯地址输入错误：应为正整数", e.ColumnIndex);
					if (LanguageOper.available == true)
					{
						msg = string.Format(LanguageOper.ReadValue(section, "msgStr.14"), e.ColumnIndex);
					}

					MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);

					if (currentSubIndex != -1)
					{
						portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = subList[currentSubIndex].portList[e.ColumnIndex - 1].startLampAddr.ToString();
					}
				}
				else
				{
					if (currentSubIndex != -1)
					{
						subList[currentSubIndex].portList[e.ColumnIndex - 1].startLampAddr = startAddrValue;
						calcDmx512Addr();
						// 更新界面（某一列）
						if (showDmxAddrCheckBox.Checked)
						{
							for (int rowIndex = headRowNum; rowIndex < portDataGridView.Rows.Count; rowIndex++)
							{
								int portIndex = e.ColumnIndex - 1;
								int lampIndex = rowIndex - headRowNum;
								if (lampIndex > subList[currentSubIndex].portList[portIndex].lampList.Count - 1)
								{
									break;
								}
								string channelStr = subList[currentSubIndex].portList[portIndex].lampList[lampIndex].channelStr.ToString();
								string dmxAddrDtr = subList[currentSubIndex].portList[portIndex].lampList[lampIndex].dmxAddr.ToString();
								if (!channelStr.Equals(""))
								{
									portDataGridView.Rows[rowIndex].Cells[e.ColumnIndex].Value = channelStr + "(" + dmxAddrDtr + ")";
								}
							}
						}
					}
				}
			}

			// 灯具地址数据区
			if (e.RowIndex >= headRowNum)
			{
				string valueStr = "";
				if (portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
				{
					valueStr = portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString().Trim();
				}
				
				if (showDmxAddrCheckBox.Checked == true && !valueStr.Equals(""))
				{
					valueStr = valueStr.Split('(')[0];
				}

				if (valueStr.Equals(""))
				{
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].channelStr = "";
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].dmxAddr = 0;
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].errorFlag = false;

					calcDmx512Addr();

					// 更新界面（某一列）
					if (showDmxAddrCheckBox.Checked)
					{
						for (int rowIndex = headRowNum; rowIndex < portDataGridView.Rows.Count; rowIndex++)
						{
							int portIndex = e.ColumnIndex - 1;
							int lampIndex = rowIndex - headRowNum;
							if (lampIndex > subList[currentSubIndex].portList[portIndex].lampList.Count - 1)
							{
								break;
							}
							string channelStr = subList[currentSubIndex].portList[portIndex].lampList[lampIndex].channelStr.ToString();
							string dmxAddrDtr = subList[currentSubIndex].portList[portIndex].lampList[lampIndex].dmxAddr.ToString();
							if (!channelStr.Equals(""))
							{
								portDataGridView.Rows[rowIndex].Cells[e.ColumnIndex].Value = channelStr + "(" + dmxAddrDtr + ")";
							}
						}
					}
					return;
				}

				int addrValue = -1;
				bool res = int.TryParse(valueStr, out addrValue);
				bool errorFlag = false;
				if (res == false || addrValue < 1 || addrValue > 4096)
				{
					errorFlag = true;
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].channelStr = "";
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].errorFlag = false;
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].dmxAddr = 0;
				}
				else
				{
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].channelStr = valueStr;
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].errorFlag = false;
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].dmxAddr = 0;
					portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BackColor = Color.White;
				}
				
				calcDmx512Addr();

				// 更新界面（某一列）
				if (showDmxAddrCheckBox.Checked)
				{
					for (int rowIndex = headRowNum; rowIndex < portDataGridView.Rows.Count; rowIndex++)
					{
						int portIndex = e.ColumnIndex - 1;
						int lampIndex = rowIndex - headRowNum;
						if (lampIndex > subList[currentSubIndex].portList[portIndex].lampList.Count - 1)
						{
							break;
						}
						string channelStr = subList[currentSubIndex].portList[portIndex].lampList[lampIndex].channelStr.ToString();
						string dmxAddrDtr = subList[currentSubIndex].portList[portIndex].lampList[lampIndex].dmxAddr.ToString();
						if (!channelStr.Equals(""))
						{
							portDataGridView.Rows[rowIndex].Cells[e.ColumnIndex].Value = channelStr + "(" + dmxAddrDtr + ")";
						}
					}
				}
				if (errorFlag == true)
				{
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].channelStr = "";
					subList[currentSubIndex].portList[e.ColumnIndex - 1].lampList[e.RowIndex - headRowNum].dmxAddr = 0;
					portDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
				}
			}
		}

		// 端口数据区 - 垂直滚动条滚动, 判断端口选择 CheckBox 是否显示
		private void portDataGridView_Scroll(object sender, ScrollEventArgs e)
		{
			if (e.NewValue == 0)
			{
				for (int i = 0; i < 8; i++)
				{
					portCheckBoxList[i].Visible = true;
				}
				portCheckBoxIsShown = true;
			}
			else if (portCheckBoxIsShown == true)
			{
				for (int i = 0; i < 8; i++)
				{
					portCheckBoxList[i].Visible = false;
				}
				portCheckBoxIsShown = false;
			}
		}

		// 端口数据区 - 端口选中项变化
		private void portCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			CheckBox portCheckBox = (CheckBox)sender;
			int portIndex = int.Parse(portCheckBox.Name.Substring("portCheckBox".Length));
			if (currentSubIndex != -1)
			{
				subList[currentSubIndex].portList[portIndex].hasChecked = portCheckBox.Checked;
			}
		}

        //打开文件
        private void datFileButton_Click(object sender, EventArgs e) {
            var dialog = new OpenFileDialog();
            dialog.FilterIndex = 0;
            dialog.RestoreDirectory = true;
            dialog.Filter = "XML File(*.xml)|*.xml";
            if (dialog.ShowDialog() != DialogResult.OK) {
                return;
            }

            var path = dialog.FileName;
            datFileTextBox.Text = path;
            var config = SubPortDataConfig.LoadFromFile(path);
            loadConfig(config);
        }

        //保存
        private void btnSave_Click(object sender, EventArgs e) {
            var dialog = new SaveFileDialog();
            dialog.FilterIndex = 0;
            dialog.RestoreDirectory = true;
            dialog.Filter = "XML File(*.xml)|*.xml";
            if (dialog.ShowDialog() != DialogResult.OK) {
                return;
            }

            var path = dialog.FileName;
            var config = genConfig();
            if (config != null) {
                config.SaveToFile(path);
            }
        }

		#endregion

		#region 内部逻辑

		// 新建 - 创建内部数据结构
		private void buildNewData()
		{
			if (subNum_new <= 0 || lampNum_new <= 0)
			{
				return;
			}

			// 创建内部数据结构
			subList.Clear();
			for (int i = 0; i < subNum_new; i++)
			{
				subList.Add(new AddrSub(lampNum_new));
			}
		}

		// 初始化分控列表（左侧）
		private void initSubDataGridView()
		{
			initDone = false;

			// 清除原有界面显示
			subDataGridView.Rows.Clear();

			// 初始化当前界面显示
			string formatStr1 = "控制器{0,-2}";
			string formatStr2 = "控制器{0,-3}";
			if (LanguageOper.available == true)
			{
				formatStr1 = LanguageOper.ReadValue(section, "str.0");
				formatStr2 = LanguageOper.ReadValue(section, "str.1");
			}

			if (subList.Count < 100)
			{
				for (int i = 0; i < subList.Count; i++)
				{
					subDataGridView.Rows.Add(false, String.Format(formatStr1 + " ({1})", i + 1, subList[i].getTotalLampNum()));
				}
			}
			else
			{
				for (int i = 0; i < subList.Count; i++)
				{
					subDataGridView.Rows.Add(false, String.Format(formatStr2 + " ({1})", i + 1, subList[i].getTotalLampNum()));
				}
			}

			initDone = true;
		}

		// 刷新分控列表（左侧）
		private void updateSubDataGridView(int subIndex)
		{
			string formatStr1 = "控制器{0,-2}";
			string formatStr2 = "控制器{0,-3}";
			if (LanguageOper.available == true)
			{
				formatStr1 = LanguageOper.ReadValue(section, "str.0");
				formatStr2 = LanguageOper.ReadValue(section, "str.1");
			}

			if (subIndex < subDataGridView.Rows.Count)
			{
				if (subList.Count < 100)
				{
					subDataGridView.Rows[subIndex].Cells[1].Value = String.Format(formatStr1 + " ({1})", subIndex + 1, subList[subIndex].getTotalLampNum());
				}
				else
				{
					subDataGridView.Rows[subIndex].Cells[1].Value = String.Format(formatStr2 + " ({1})", subIndex + 1, subList[subIndex].getTotalLampNum());
				}
			}
		}

		// 刷新端口数据列表（右侧）
		private void updatePortDataGridView(int subIndex)
		{
			if (subIndex == -1)
			{
				portDataGridView.Columns[0].HeaderText = "";
				portDataGridView.Rows.Clear();
				for (int i = 0; i < 8; i++)
				{
					portCheckBoxList[i].Visible = false;
				}
				currentSubIndex = -1;
			}

			// 存在分控数据
			if (subIndex >= 0 && subIndex <= subList.Count - 1)
			{
				portDataGridView.Rows.Clear();
				for (int i = 0; i < 8; i++)
				{
					portCheckBoxList[i].Checked = subList[subIndex].portList[i].hasChecked;
					portCheckBoxList[i].Visible = false;
				}
				portCheckBoxIsShown = false;

				AddrSub addrSub = subList[subIndex];

				string text = "选择端口->";
				string formatStr1 = "[ 控制器 {0} ]";
				string text2 = "首灯地址->";
				string text3 = "灯具序号 -";
				if (LanguageOper.available == true)
				{
					text = LanguageOper.ReadValue(section, "str.2");
					formatStr1 = LanguageOper.ReadValue(section, "str.3");
					text2 = LanguageOper.ReadValue(section, "str.4");
					text3 = LanguageOper.ReadValue(section, "str.5");
				}

				portDataGridView.Rows.Add(text, "", "", "", "", "", "", "", "");

				for (int i = 1; i <= 8; i++)
				{
					portDataGridView.Rows[0].Cells[i].ReadOnly = true;
					portDataGridView.Rows[0].Cells[i].Style.SelectionBackColor = Color.White;
					System.Drawing.Rectangle rect = portDataGridView.GetCellDisplayRectangle(i, 0, true);
					if (getMaxPortLampNum(subIndex) >= 16)
					{
						portCheckBoxList[i - 1].Location = new Point(rect.Location.X + 3, rect.Location.Y + 1);
					}
					else
					{
						portCheckBoxList[i - 1].Location = new Point(rect.Location.X + 19, rect.Location.Y + 1);
					}
					portCheckBoxList[i - 1].Visible = true;
				}
				portCheckBoxIsShown = true;

				portDataGridView.Columns[0].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleLeft;
				portDataGridView.Columns[0].HeaderText = String.Format(formatStr1, subIndex + 1);
				portDataGridView.Rows.Add(text2, addrSub.portList[0].startLampAddr, addrSub.portList[1].startLampAddr, addrSub.portList[2].startLampAddr, addrSub.portList[3].startLampAddr,
										 addrSub.portList[4].startLampAddr, addrSub.portList[5].startLampAddr, addrSub.portList[6].startLampAddr, addrSub.portList[7].startLampAddr);
				
				int maxPortLampNum = getMaxPortLampNum(subIndex);
				bool withDmxAddr = showDmxAddrCheckBox.Checked;
				for (int lampIndex = 0; lampIndex < maxPortLampNum; lampIndex++)
				{
					string[] lampAddrStrings = new string[8];
					bool[] errorFlags = new bool[8];
					bool[] enableFlag = new bool[8];
					for (int portIndex = 0; portIndex < 8; portIndex++)
					{
						if (lampIndex < addrSub.portList[portIndex].lampList.Count)
						{
							lampAddrStrings[portIndex] = addrSub.portList[portIndex].lampList[lampIndex].channelStr.ToString();

							if (!lampAddrStrings[portIndex].Equals("") && !lampAddrStrings[portIndex].Equals("--") && withDmxAddr)
							{
								lampAddrStrings[portIndex] += "(" + addrSub.portList[portIndex].lampList[lampIndex].dmxAddr + ")";
							}
							errorFlags[portIndex] = addrSub.portList[portIndex].lampList[lampIndex].errorFlag;
							enableFlag[portIndex] = true;
						}
						else
						{
							lampAddrStrings[portIndex] = "--";
							errorFlags[portIndex] = false;
							enableFlag[portIndex] = false;
						}
					}

					portDataGridView.Rows.Add(text3 + " " + (lampIndex + 1), lampAddrStrings[0], lampAddrStrings[1], lampAddrStrings[2], lampAddrStrings[3],
													lampAddrStrings[4], lampAddrStrings[5], lampAddrStrings[6], lampAddrStrings[7]);

					int currentRowIndex = portDataGridView.Rows.Count - 1;
					for (int portIndex = 0; portIndex < 8; portIndex++)
					{
						if (errorFlags[portIndex] == true)
						{
							portDataGridView.Rows[currentRowIndex].Cells[portIndex + 1].Style.BackColor = Color.LightGray;
						}
						if (enableFlag[portIndex] == false)
						{
							portDataGridView.Rows[currentRowIndex].Cells[portIndex + 1].ReadOnly = true;
						}
					}
				}

				portDataGridView.ClearSelection();
			}
		}

		// 调整端口灯数
		private void changePortLampNum()
		{
			if (subList.Count == 0 || currentSubIndex < 0)
			{
				string msg = "请先选择控制器";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.3");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);

				return;
			}

			SubParaWriteAddrPro para = new SubParaWriteAddrPro();
			para.subIndex = currentSubIndex;
			for (int i = 0; i < 8; i++)
			{
				para.lampNum[i] = subList[currentSubIndex].portList[i].lampList.Count;
			}

			Form_SubParaWriteAddrPro paraForm = new Form_SubParaWriteAddrPro(para, "edit");
			parent.addForm("Form_SubParaWriteAddrPro", paraForm);
			paraForm.setLanguageText();
			DialogResult dr = paraForm.ShowDialog();
			parent.removeForm("Form_SubParaWriteAddrPro");
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				// 根据 para 内容修改内部数据
				AddrSub addrSub = subList[para.subIndex];
				for (int i = 0; i < 8; i++)
				{
					// 减少灯具
					if (addrSub.portList[i].lampList.Count > para.lampNum[i])
					{
						int delNum = addrSub.portList[i].lampList.Count - para.lampNum[i];
						addrSub.portList[i].lampList.RemoveRange(addrSub.portList[i].lampList.Count - delNum, delNum);
					}
					// 增加灯具
					else
					{
						int addNum = para.lampNum[i] - addrSub.portList[i].lampList.Count;
						for (int k = 0; k < addNum; k++)
						{
							addrSub.portList[i].lampList.Add(new AddrLamp());
						}
					}
				}

				updateSubDataGridView(para.subIndex);
				updatePortDataGridView(para.subIndex);
			}
		}

		// 获取单台分控单端口的最大灯点数
		private int getMaxPortLampNum(int subIndex)
		{
			if (subIndex < 0 || subIndex > subList.Count - 1)
			{
				return 0;
			}
			else
			{
				AddrSub addrSub = subList[subIndex];
				int maxPortLampNum = 0;
				foreach (AddrPort port in addrSub.portList)
				{
					if (maxPortLampNum < port.lampList.Count)
					{
						maxPortLampNum = port.lampList.Count;
					}
				}
				return maxPortLampNum;
			}
		}

		// 快速编辑
		private void quickEditHandle(Form_QuickEditAddr quickEdit)
		{
			// 备份currentSubIndex
			int currentSubIndexSave = currentSubIndex;

			for (currentSubIndex = 0; currentSubIndex < subList.Count; currentSubIndex++)
			{
				// 当前模式为：应用到选定分控，且此分控未被选中
				if (quickEdit.subMode.Equals("selected") && subDataGridView.Rows[currentSubIndex].Cells[0].Value.ToString().ToLower().Equals("false"))
				{
					continue;
				}

				if (quickEdit.subMode.Equals("current"))
				{
					if(subDataGridView.SelectedRows.Count <= 0)
					{
						continue;
					}
					else
					{
						if (currentSubIndex != subDataGridView.SelectedRows[0].Index)
						{
							continue;
						}
					}
				}

				AddrSub currentSub = subList[currentSubIndex];
				int[] channelArray = quickEdit.channelArray;

				// 首灯地址
				if (quickEdit.portIndex == 0)
				{
					// 所有端口
					for (int i = 0; i < 8; i++)
					{
						currentSub.portList[i].startLampAddr = quickEdit.startLampAddr;
					}
				}
				else if (quickEdit.portIndex == 9)
				{
					// 当前选定的端口
					for (int i = 0; i < 8; i++)
					{
						if (currentSub.portList[i].hasChecked)
						{
							currentSub.portList[i].startLampAddr = quickEdit.startLampAddr;
						}
					}
				}
				else
				{
					// 指定端口
					currentSub.portList[quickEdit.portIndex].startLampAddr = quickEdit.startLampAddr;
				}

				// 计算并填表
				int channelArrayIndex = -1;
				int startPortIndex = 0;
				int endPortIndex = 8;
				if (quickEdit.portIndex == 0 || quickEdit.portIndex == 9)
				{
					startPortIndex = 0;
					endPortIndex = 8;
				}
				else
				{
					startPortIndex = quickEdit.portIndex - 1;
					endPortIndex = quickEdit.portIndex;
				}
				for (int i = startPortIndex; i < endPortIndex; i++)
				{
					// 跳过未选的端口
					if (quickEdit.portIndex == 9 && currentSub.portList[i].hasChecked == false)
					{
						continue;
					}

					channelArrayIndex = -1;
					for (int lampNum = quickEdit.startLampNum; lampNum <= quickEdit.endLampNum; lampNum++)
					{
						channelArrayIndex++;
						if (channelArrayIndex == channelArray.Length)
						{
							channelArrayIndex = 0;
						}

						if (lampNum - 1 < currentSub.portList[i].lampList.Count)
						{
							currentSub.portList[i].lampList[lampNum - 1].channelStr = channelArray[channelArrayIndex].ToString();
						}
					}
				}

				calcDmx512Addr();
			}

			// 恢复currentSubIndex
			currentSubIndex = currentSubIndexSave;
			
			// 刷新界面
			updatePortDataGridView(currentSubIndex);
		}

		// 计算 DMX512 地址
		private void calcDmx512Addr()
		{
			if (currentSubIndex == -1)
			{
				return;
			}

			AddrSub currentSub = subList[currentSubIndex];
			
			for (int i = 0; i < 8; i++)
			{
				int currentDmxAddr = currentSub.portList[i].startLampAddr;
				for (int k = 0; k < currentSub.portList[i].lampList.Count; k++)
				{
					if (currentSub.portList[i].lampList[k].channelStr.Equals(""))
					{
						currentSub.portList[i].lampList[k].dmxAddr = 0;
						continue;
					}

					currentSub.portList[i].lampList[k].dmxAddr = currentDmxAddr;
					currentDmxAddr += int.Parse(currentSub.portList[i].lampList[k].channelStr);
				}
			}
		}

		// 检查当前要写入的数据中是否有空地址
		private bool hasEmptyAddrLamp()
		{
			bool hasEmptyAddrLamp = false;
			subIndexEmpty = -1;
			portIndexEmpty = -1;
			
			for (int subIndex = 0; subIndex < subDataGridView.RowCount; subIndex++)
			{
				if (hasEmptyAddrLamp == true)
				{
					break;
				}

				if (subDataGridView.Rows[subIndex].Cells[0].Value.ToString().ToLower().Equals("true"))
				{
					for (int portIndex = 0; portIndex < 8; portIndex++)
					{
						if (hasEmptyAddrLamp == true)
						{
							break;
						}

						if (subList[subIndex].portList[portIndex].hasChecked == true)
						{
							foreach(AddrLamp addrLamp in subList[subIndex].portList[portIndex].lampList)
							{
								if (addrLamp.channelStr.Equals("") && addrLamp.dmxAddr == 0)
								{
									hasEmptyAddrLamp = true;
									subIndexEmpty = subIndex;
									portIndexEmpty = portIndex;
									break;
								}
							}
						}
					}
				}
			}

			return hasEmptyAddrLamp;
		}

		// 开始写入 DMX 地址
		private bool startWriteDmxAddr()
		{
			needWriteNum = 0;
			for (int subIndex = 0; subIndex < subDataGridView.RowCount; subIndex++)
			{
				if (subDataGridView.Rows[subIndex].Cells[0].Value.ToString().ToLower().Equals("true"))
				{
					for (int portIndex = 0; portIndex < 8; portIndex++)
					{
						// 选中的分控和端口
						if (subList[subIndex].portList[portIndex].hasChecked == true)
						{
							needWriteNum++;
						}
					}
				}
			}
			if (needWriteNum == 0)
			{
				string msg = "请选择要写入的分控和端口";
				if (LanguageOper.available == true)
				{
					msg = LanguageOper.ReadValue(section, "msgStr.15");
				}

				MessageBoxEx.Show(this, msg, tip, MessageBoxButtons.OK, MessageBoxIcon.None);
				
				return false;
			}
			else
			{
				forceStop = false;
				Thread t = new Thread(writeDmxAddrProcess);
				t.IsBackground = true;
				t.Start();
				
				return true;
			}
		}

		// 写入 DMX 地址 - 实际动作，线程方法
		private void writeDmxAddrProcess()
		{
			writeDmxIsProcessing = true;

			int doneNum = 0;
			for (int subIndex = 0; subIndex < subDataGridView.RowCount; subIndex++)
			{
				if (forceStop)
				{
					// 触发强制停止事件
					WriteProcessStopedEvent(null, new EventArgs());
					return;
				}

				if (subDataGridView.Rows[subIndex].Cells[0].Value.ToString().ToLower().Equals("true"))
				{
					for (int portIndex = 0; portIndex < 8; portIndex++)
					{
						// 选中的分控和端口
						if (subList[subIndex].portList[portIndex].hasChecked == true)
						{
							int[] dmxAddrArray = subList[subIndex].portList[portIndex].getDmxAddrArray();
							int startAddr = subList[subIndex].portList[portIndex].startLampAddr;

							baseCoreNet.writeSubDmxStartAddrPro(subIndex + 1, portIndex, dmxAddrArray, startAddr, dmx_w_type, usePin4);

							// 等待固定的时间间隔
							int sleepTime = 0;
							while (true)
							{
								Thread.Sleep(500);
								sleepTime += 500;
								if (forceStop)
								{
									// 触发强制停止事件
									WriteProcessStopedEvent(null, new EventArgs());
									return;
								}
								if (sleepTime >= writePortTimeGap * 1000)
								{
									break;
								}
							}

							// 触发进度更新事件
							doneNum++;
							WriteProcessChangedEvent(null, new WriteProcessChangedEventArgs(doneNum * 100 / needWriteNum));
						}
					}
				}
			}
			if (forceStop == false)
			{
				// 触发写址完成事件
				WriteProcessDoneEvent(null, new EventArgs());
			}
		}

        //载入数据并更新UI
        private void loadConfig(SubPortDataConfig config) {
            if (config == null) {
                return;
            }
            var subs = config.Items;
            if (subs == null || subs.Count == 0) {
                return;
            }
            subList = new List<AddrSub>();
            for (var i = 0; i < subs.Count;i++ ) {
                var sub = subs[i];
                var ports = sub.Data;
                if (ports == null || ports.Count == 0) {
                    continue;
                }
                var arrPort = new int[8];
                var arrEnable = new bool[8];
                var arrStartLampAddr = new int[8];
                var lampLists = new List<List<AddrLamp>>();
                for (var j = 0; j < ports.Count; j++) {
                    var str = ports[j].Data;
                    var items = str.Trim().Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
                    if (items == null || items.Length < 2) {
                        continue;
                    }
                    var enable = bool.Parse(items[0]);
                    arrEnable[j] = enable;
                    var addr = int.Parse(items[1]);
                    addr = Math.Max(1, addr);
                    arrStartLampAddr[j] = addr;
                    var lampList = new List<AddrLamp>();
                    for (var m = 2; m < items.Length; m++) {
                        var chanStr = items[m];
                        var lamp = new AddrLamp();
                        lamp.channelStr = chanStr;
                        var chanNum = 0;
                        if (int.TryParse(chanStr, out chanNum)) {
                            lamp.dmxAddr = addr;
                            addr += chanNum;
                        }
                        lampList.Add(lamp);
                    }
                    lampLists.Add(lampList);
                }
                var addrSub = new AddrSub(arrPort);
                var list = addrSub.portList;
                for (var k = 0; k < list.Count; k++) {
                    list[k].hasChecked = arrEnable[k];
                    list[k].startLampAddr = arrStartLampAddr[k];
                    list[k].lampList = lampLists[k];
                }
                subList.Add(addrSub);
            }

            initSubDataGridView();
            currentSubIndex = 0;
            updateSubDataGridView(currentSubIndex);
            updatePortDataGridView(currentSubIndex);
        }

        private SubPortDataConfig genConfig() {
            if (subList == null || subList.Count == 0) {
                return null;
            }
            SubPortDataConfig config = new SubPortDataConfig();
            config.Items = new List<ControlItem>();
            for (var i = 0; i < subList.Count; i++) {
                var sub = subList[i];
                if (sub == null) {
                    continue;
                }
                var portList = sub.portList;
                if (portList == null || portList.Count == 0) {
                    continue;
                }
                var item = new ControlItem();
                item.Index = i;
                item.Data = new List<PortConfig>();
                for (var j = 0; j < portList.Count;j++ ) {
                    var port = portList[j];
                    if (port == null) {
                        continue;
                    }
                    var list = port.lampList;
                    var portCfg = new PortConfig();
                    portCfg.Index = j;
                    var str = "";
                        var maxLampNum = getMaxPortLampNum(i);
                    if (list == null || list.Count == 0) {
                        str += "False#1";
                        for (var k = 0; k < maxLampNum; k++) {
                            str += "#";
                        }
                    } else {
                        if (port.hasChecked) {
                            str += "True#";
                            str += port.startLampAddr;
                        } else {
                            str += "False#";
                            str += 1;
                        }
                        for (var k = 0; k < maxLampNum; k++) {
                            str += "#";
                            if (k < list.Count) {
                                var lamp = list[k];
                                str += lamp.channelStr;
                            }
                        }
                    }
                    portCfg.Data = str;
                    item.Data.Add(portCfg);
                }
                config.Items.Add(item);
            }

            return config;
        }

		#endregion

	}

	public class AddrSub
	{
		public List<AddrPort> portList;

		public AddrSub(int lampNum)
		{
			portList = new List<AddrPort>();
			for(int i = 0; i < 8; i++)
			{
				portList.Add(new AddrPort(lampNum));
			}
		}

		public AddrSub(int[] lampNum)
		{
			portList = new List<AddrPort>();
			for (int i = 0; i < 8; i++)
			{
				portList.Add(new AddrPort(lampNum[i]));
			}
		}

		public int getTotalLampNum()
		{
			int totalLampNum = 0;
			foreach (AddrPort addrPort in portList)
			{
				totalLampNum += addrPort.lampList.Count;
			}
			return totalLampNum;
		}
	}

	public class AddrPort
	{
		public bool hasChecked = true;

		public int startLampAddr = 1;

		public List<AddrLamp> lampList;

		public AddrPort(int lampNum)
		{
			lampList = new List<AddrLamp>();
			for(int i = 0; i < lampNum; i++)
			{
				lampList.Add(new AddrLamp());
			}
		}

		public void clearAddrData()
		{
			foreach (AddrLamp lamp in lampList)
			{
				lamp.channelStr = "";
				lamp.errorFlag = false;
			}
		}

		public int[] getDmxAddrArray()
		{
			int[] dmxAddrArray = new int[512];
			int count = lampList.Count > 512 ? 512 : lampList.Count;
			for (int i = 0; i < count; i++)
			{
				dmxAddrArray[i] = lampList[i].dmxAddr;
			}
			return dmxAddrArray;
		}
	}

	public class AddrLamp
	{
		public string channelStr = "";

		public int dmxAddr = 0;

		public bool errorFlag = false;
	}

	public class SubParaWriteAddrPro
	{
		public int subIndex = -1;

		public int[] lampNum = new int[8];
	}

	public class StartEnd
	{
		public int start = 0;

		public int end = 0;
	}

	public class WriteProcessChangedEventArgs : EventArgs
	{
		public int processValue = 0;

		public WriteProcessChangedEventArgs(int value)
		{
			processValue = value;
		}
	}

    public class ControlItem {
        [XmlAttribute("ID")]
        public int Index { get; set; }

        [XmlElement("Port")]
        public List<PortConfig> Data { get; set; }
    }

    public class PortConfig {
        [XmlAttribute("ID")]
        public int Index { get; set; }

        [XmlText]
        public string Data { get; set; }
    }

    public class SubPortDataConfig {
        [XmlElement("ControlItem")]
        public List<ControlItem> Items { get; set; }

        public void SaveToFile(string path) {
            try {
                using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
                    var xs = XmlSerializer.FromTypes(new Type[] { typeof(SubPortDataConfig) })[0];
                    xs.Serialize(fs, this);
                }
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }
        }

        public static SubPortDataConfig LoadFromFile(string path) {
            SubPortDataConfig config = null;

            try {
                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
                    var xs = XmlSerializer.FromTypes(new Type[] { typeof(SubPortDataConfig) })[0];
                    config = (SubPortDataConfig)xs.Deserialize(fs);
                }
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            return config;
        }
    }
}
